#ifndef __OBJECT_H__
#define __OBJECT_H__

#include <unistd.h>

/* 
  Maximum length of any file/directory name, (including a NULL char at end)
*/
#define MAX_FNAME_LEN 50

/* 
  Some constants, which can be changed at will
*/
#define TYPELEN 1
#define IDLEN 10
#define VERLEN 5
#define DEVLEN 2

#define ID_STRING_LENGTH (TYPELEN+1+IDLEN+1+VERLEN+1+DEVLEN+1)


/* 
  These depend on the length specified above
*/
#define MAXVER 99999
#define MAXDEV 99

#define PREFIX "/tmp/fusedata/"


/*
  Maximum number of bytes of any data object. 
  A directory and file object has no limit (you would not be using this 
  thing if you have to deal with those big a files and directories, but
  even if you do, you can do that with a little performance hit)
*/
#define MAX_DATA_OBJ 500000

typedef struct {
  unsigned char key[32];
  unsigned char iv[32];
} aeskey;



typedef enum {
  DATA_OBJ,   /* r */
  FILE_OBJ,   /* f */
  DIR_OBJ,    /* d */
} object_type;

/* 
  Typical Object ID. Version and device are kept visible, in case any
  backup tool wants to get some previous version of a file. It would be
  hard to make that change later
*/
typedef struct {
  object_type type;   /* r, f, d*/
  char id[IDLEN];     /* Some unique identifier for this object */
  /* These should be less than MAXVER and MAXDEV */
  int ver;            /* version number of this object */
  int dev;            /* Who created this? Tie with version number*/
  aeskey key;         /* Each object has to have a key */
} object_id;

/* Typical directory entry */
typedef struct {
  char name[MAX_FNAME_LEN]; /* name of the file or sub-dir, ends with NULL */
  object_id obj_id;         /* the file/data object. This better be
                            without any version number */
  /* Other meta-data can be added here at will */
} dentry;


/*
  In case of a sparse object, the object-ID is set to r-0000000..., which
  is handled differently at the FUSE level. It is an error to request 
  such objects from the [get|put]_object
*/
typedef struct {
  object_id obj_id;     /* Object ID of data object */
  off_t offset;         /* Offset in the file (facilitates sparse files*/
  size_t size;          /* Length of this particular data object */
} fentry;

typedef struct {
  object_type type; /* Type of object */
  size_t length;          /* Length of the variable part */
  /*
    The variable part of the object. This is raw data for a data
    object, list of fentry's for a file, and a list of dentry's 
    for a dir object 
  */ 
  void *data;
} object;

/* 
  We need this to be visible to other routines that will
  be interacting with object_dir 
*/
void object_id_to_string (char *str, object_id *id);


/*
  Reads the object (data, file, or dir) pointed to by ID, populates
  OBJ and copies the raw data in BUF, if total length of the raw data
  is less than MAX_LENGTH.
  If the Versioning info is present in ID, uses that. Otherwise 
  returns the latest version. Usually it should not be there.
  Returns the number of actual bytes copied to BUF in case of success.
  Returns -1 in case MAX_LENGTH is not sufficient to hold the full object. 
  [Which implies that the objects are read always in full]
*/
int get_object (object_id *id, object *obj, 
                  size_t max_length, char *buf);

/* 
  Puts OBJ at ID, length and data are already set up properly.
  Versioning information should not be included. It is the 
  responsibility of the caching service to set versioning.
*/
void put_object (object_id *id, object *obj);

#endif  /* End of __OBJECT_H__ */
